/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.changeconvertor.methodgenerator;

import com.inspur.edp.bff.designtime.generator.changeconvertor.FSChangeConvertorGenContext;
import com.inspur.edp.bff.spi.AbstractChangeConvertor;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import lombok.var;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.Arrays;

public class GetChildChangeConvertorGenerator extends ClassMethodGenerator {

    private static final String paramChildCode = "childCode";
    private FSChangeConvertorGenContext changeConvertorContext;
    private boolean hasChild = false;

    public GetChildChangeConvertorGenerator(FSChangeConvertorGenContext changeConvertorContext) {
        this.changeConvertorContext = changeConvertorContext;
    }

    @Override
    protected Block buildMethodBody() {

        var block = ast.newBlock();
        SwitchStatement result = getSwitchBlock();
        ArrayList<Statement> statements = getChildCases();

        statements.addAll(getDefaultCase());
        result.statements().addAll(statements);
        return buildReturnBlock(result);
    }

    private SwitchStatement getSwitchBlock() {
        SwitchStatement statement = ast.newSwitchStatement();
        statement.setExpression(ast.newSimpleName(paramChildCode));
        return statement;
    }

    private Block buildReturnBlock(SwitchStatement result) {
        var block = ast.newBlock();
        if (hasChild) {
            block.statements().add(result);
        } else {
            block.statements().add(ExpressionUtils.getReturnNullStatement(ast));
//            block.statements().add(getExceptionStatement());
        }
        return block;
    }

    private ArrayList<Statement> getChildCases() {

        ArrayList<Statement> statements = new ArrayList<>();
        for (IGspCommonObject childObj : changeConvertorContext.getVmObject().getContainChildObjects()) {
            GspViewObject item = (GspViewObject)childObj;
            if (item.getIsVirtual() || item.getMapping().getTargetMetadataId() .equals(changeConvertorContext
                    .getVmGeneratorContext().getRefBizEntity().getID())==false) {
                continue;
            }
            hasChild = true;
            statements.addAll(getChildCase(item));
        }
        return statements;
    }

    //        case object.Code:
//      * return new objectConvertor();
//      
    private ArrayList<Statement> getChildCase(GspViewObject vmObject) {

        ArrayList<Statement> statements = new ArrayList<>();

        statements.add(getSwitchCase(vmObject.getCode()));

        var className = changeConvertorContext.getChildGenerators().get(vmObject.getID()).getClassName();
        var returnStatement = ast.newReturnStatement();
        var creation = ast.newClassInstanceCreation();
        creation.setType(ast.newSimpleType(ast.newSimpleName(className)));
        var methodArg = ast.newMethodInvocation();
        methodArg.setName(ast.newSimpleName("getMgrContext"));
        creation.arguments().add(methodArg);
        returnStatement.setExpression(creation);
        statements.add(returnStatement);

        return statements;
    }

    private SwitchCase getSwitchCase(String value) {
        var caseValue = ast.newStringLiteral();
        caseValue.setLiteralValue(value);
        var caseStatement = ast.newSwitchCase();
        caseStatement.setExpression(caseValue);

        return caseStatement;
    }
    private ArrayList<Statement> getDefaultCase() {
        ArrayList<Statement> statements = new ArrayList<>();
        var defaultStatement= ast.newSwitchCase();
        defaultStatement.setExpression(null);
        statements.add(defaultStatement);
//        statements.add(getExceptionStatement());
        statements.add(ExpressionUtils.getReturnNullStatement(ast));
        return statements;
    }

    private ThrowStatement getExceptionStatement() {
        addImport(CefException.class.getTypeName());
        ThrowStatement statement = GeneratorUtil.getThrowStatement(ast,"不存在子表",paramChildCode,true);

//        var invocation = ast.newClassInstanceCreation();
//        invocation.setType(ast.newSimpleType(ast.newSimpleName("RuntimeException")));
//        invocation.setType(new TypeInfo(RuntimeException.class).getType(ast, changeConvertorContext.getEntityGenContext()));
//        var message = ast.newInfixExpression();
//        var format = ast.newStringLiteral();
//        format.setLiteralValue("不存在子表");
//        message.setLeftOperand(format);
//        message.setOperator(InfixExpression.Operator.PLUS);
//        message.setRightOperand(ast.newSimpleName(paramChildCode));
//
//        invocation.arguments().add(message);
//        statement.setExpression(invocation);

        return statement;
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        return new ArrayList<Modifier.ModifierKeyword>(Arrays.asList(
                new Modifier.ModifierKeyword[]{Modifier.ModifierKeyword.PROTECTED_KEYWORD}));
    }

    @Override
    protected boolean getIsOverride() {
        return true;
    }

    @Override
    protected String getMethodName() {
        return "getChildChangeConvertor";
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        ParameterInfo parameterInfo = new ParameterInfo();
        parameterInfo.setParamType(new TypeInfo(String.class));
        parameterInfo.setParamName(paramChildCode);
        return new ArrayList<ParameterInfo>(
                Arrays.asList(new ParameterInfo[]{parameterInfo}));
    }

    @Override
    protected TypeInfo getReturnType() {
        return new TypeInfo(AbstractChangeConvertor.class);
    }
}
